package com.qdd.freight.util;

import com.qdd.freight.constant.NumberConstants;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class SecurityUtil {
    /***
     * @author fanshuai
     * @Description 返回京东加密报文MD5
     * @Time 2013-5-18
     * @param plainText
     * @return
     */
    public static String getJingDongDigest(String plainText) {
        String str = DigestUtils.md5Hex(plainText);

        return str;
    }

    /***
     * @author fanshuai
     * @Description 返回MD5之后的字节数组
     * @Time 2013-7-3
     * @param plainText
     * @param charset
     * @return
     * @throws UnsupportedEncodingException
     * @throws Exception
     */
    private static byte[] mD5Byte(String plainText, String charset)
            throws UnsupportedEncodingException {
        return DigestUtils.md5(plainText.getBytes(charset));

    }

    /***
     * @author fanshuai
     * @Description 返回Base64加密字符串
     * @Time 2013-5-18
     * @param plainText
     * @return
     */
    public static String base64(String plainText) {
        return Base64.encodeBase64String(plainText.getBytes());
    }

    /***
     * @author fanshuai
     * @Description 先MD5加密，再Base64加密，通用
     * @Time 2013-5-24
     * @param plainText
     * @param charset
     * @return
     * @throws Exception
     * @throws
     */
    public static String getCommonDigest(String plainText, String charset) {
        return getDigest(plainText);

    }

    /***
     * @author fanshuai
     * @Description 淘宝的摘要加密，先MD5,再BASE64
     * @Time 2013-7-3
     * @param plainText
     *            加密前的普通文本
     * @param charset
     *            加密用到的编码方式
     * @return
     */
    public static String getTaobaoDigest(String plainText, String charset) {
        try {
            return new String(Base64.encodeBase64(mD5Byte(plainText, charset)),
                    charset);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 菜鸟下单、订单更新签名加密方法；菜鸟轨迹推送还是使用getTaobaoDigest
     *
     * @param plainText
     * @param charset
     * @return
     */
    public static String getCainiaoDigest(String plainText, String charset) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes(charset));
            String str = new String(Base64.encodeBase64(md.digest()), charset);
            return str;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * @author fanshuai
     * @Description 阿里巴巴摘要验证
     * @Time 2013-7-3
     * @param plainText
     * @return
     */
    public static String getAlibabaDigest(String plainText) {
        return Base64.encodeBase64String(DigestUtils.md5Hex(plainText)
                .getBytes());
    }

    /***
     * @author fanshuai
     * @Description 阿里巴巴摘要验证 切换成PAC平台加密
     * @Time 2015-01-11
     * @param plainText
     * @return
     */
    public static String getAlibabaPACDigest(String plainText) {
        String sign;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes("utf-8"));
            sign = new String(Base64.encodeBase64(md.digest()), "utf-8");
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
        return sign;
    }

    /***
     * @author fanshuai
     * @Description 金蝶。与阿里巴巴一致
     * @Time 2013-7-3
     * @param plainText
     * @return
     */
    public static String getKingdeeDigest(String plainText) {
        return getDigest(plainText);
    }

    /***
     * @author hufei
     * @Description 与阿里巴巴一致
     * @Time 2015-5-20
     * @param plainText
     * @return
     */
    public static String getTAOBAOJZDigest(String plainText) {
        return getDigest(plainText);
    }

    /***
     * @author fanshuai
     * @Description QQ速递
     * @Time 2013-7-3
     * @param plainText
     * @return
     */
    public static String getQQSudiDigest(String plainText) {
        return getDigest(plainText);
    }

    /***
     * @author huzhenqi
     * @Description 标准通用
     * @Time 2013-11-5
     * @param plainText
     * @return
     */
    public static String getStandardDigest(String plainText) {
        return getDigest(plainText);
    }

    public static String getDigest(String plainText) {
        return Base64.encodeBase64String(DigestUtils.md5Hex(plainText)
                .getBytes());
    }

    /**
     * @param sourceString
     * @return
     * @author 李鹏飞
     * @Description SHA1加密
     * @Time 2013-7-7
     */
    public static String sHA1Encode(String sourceString) {
        String resultString = null;
        try {
            resultString = new String(sourceString);
            MessageDigest md = MessageDigest.getInstance("SHA1");
            byte[] bytes = md.digest(resultString.getBytes());
            StringBuffer buf = new StringBuffer(bytes.length * 2);
            for (int i = 0; i < bytes.length; i++) {
                if ((bytes[i] & NumberConstants.HEX_255) < NumberConstants.HEX_16) {
                    buf.append("0");
                }
                buf.append(Long.toString(bytes[i] & NumberConstants.HEX_255,
                        NumberConstants.DECIMAL_16));
            }
            resultString = buf.toString();
        } catch (Exception ex) {
            ex.printStackTrace();
            resultString = "";
        }
        return resultString;
    }

    public static String getMicrocreditDigest(String plainText, String charset) {
        String digest = "";
        try {
            digest = DigestUtils.md5Hex(plainText.getBytes(charset));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return digest;
    }

    /**
     * @param length
     * @return
     * @author 张佳懿
     */
    public static String randomString(int length) {
        if (length < 1) {
            return null;
        }
        String basicchars = "0123456789abcdefghijklmnopqrstuvwxy";
        // "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        Random randGen = new Random();
        char[] numbersAndLetters = basicchars.toCharArray();
        char[] randBuffer = new char[length];
        for (int i = 0; i < randBuffer.length; i++) {
            randBuffer[i] = numbersAndLetters[randGen.nextInt(basicchars
                    .length() - 1)];
        }
        return new String(randBuffer);
    }

    public static String getMD5Str(String str) {
        MessageDigest messageDigest = null;
        StringBuffer md5StrBuff = new StringBuffer();
        try {
            messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(str.getBytes("UTF-8"));
            byte[] byteArray = messageDigest.digest();

            for (int i = 0; i < byteArray.length; i++) {
                if (Integer.toHexString(NumberConstants.HEX_255 & byteArray[i])
                        .length() == 1) {
                    md5StrBuff.append("0").append(
                            Integer.toHexString(NumberConstants.HEX_255
                                    & byteArray[i]));
                } else {
                    md5StrBuff.append(Integer.toHexString(NumberConstants.HEX_255
                            & byteArray[i]));
                }
            }
        } catch (NoSuchAlgorithmException e) {
            System.out.println("NoSuchAlgorithmException caught!");
            md5StrBuff.append("");
            System.exit(-1);
        } catch (Exception e) {
            e.printStackTrace();
            md5StrBuff.append("");
            System.exit(-1);
        }

        return md5StrBuff.toString();
    }

    /**
     * 酒仙网 md5
     *
     * @param shippingId
     * @param xml
     * @return
     * @throws Exception
     */
    public static String getVerifyData(String shippingId, String xml,
                                       String strConst) {
        String verify = null;
        String rdm1 = randomString(NumberConstants.DECIMAL_4);
        String rdm2 = randomString(NumberConstants.DECIMAL_4);
        String str = rdm1 + shippingId + xml + strConst + rdm2;
        String strmd5 = getMD5Str(str);
        verify = rdm1
                + strmd5.substring(NumberConstants.DECIMAL_7,
                NumberConstants.DECIMAL_28) + rdm2;
        return verify;
    }

    /** ---------- 菜鸟异常单查询接口（聚石塔API规范） Start ---------- */

    /**
     * @return 32 character
     * @description 32位 MD5加密结果 目前为菜鸟聚石塔异常单查询对接使用
     * @date 2015-09-08
     * @author ZHOUXI
     */
    public static String md5Signature(TreeMap<String, String> params,
                                      String secret) {

        String result = null;
        // 聚石塔加密要求首部分加入secret
        StringBuffer orgin = getBeforeSign(params, new StringBuffer(secret));
        // treeMap无值有效性验证
        if (orgin == null) {
            return result;
        }
        // 聚石塔加密要求尾部分加入secret
        orgin.append(secret);

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            result = byte2hex(md.digest(orgin.toString().getBytes("utf-8")));

        } catch (Exception e) {
            throw new RuntimeException(
                    "TOP_API_PARAM has to MD5_Sign was Error !");
        }

        return result;
    }

    /**
     * 保持插入顺序而使用LinkedHashMap重载同名方法
     */
    public static String md5Signature(LinkedHashMap<String, String> params,
                                      String secret) {

        String result = null;
        // 聚石塔加密要求首部分加入secret
        StringBuffer orgin = getBeforeSign(params, new StringBuffer(secret));
        // treeMap无值有效性验证
        if (orgin == null) {
            return result;
        }
        // 聚石塔加密要求尾部分加入secret
        orgin.append(secret);

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            result = byte2hex(md.digest(orgin.toString().getBytes("utf-8")));

        } catch (Exception e) {
            throw new RuntimeException(
                    "TOP_API_PARAM has to MD5_Sign was Error !");
        }

        return result;
    }

    /**
     * 二行制转字符串（toHex）
     */
    private static String byte2hex(byte[] b) {

        StringBuffer hs = new StringBuffer();

        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            // 将byte值取十六进制字符
            stmp = (Integer.toHexString(b[n] & 0XFF));
            // 十六进制字符拼接
            if (stmp.length() == 1) {
                hs.append("0").append(stmp);
            } else {
                hs.append(stmp);
            }
        }

        return hs.toString().toUpperCase();
    }

    /**
     * 添加参数的封装方法
     */
    private static StringBuffer getBeforeSign(TreeMap<String, String> params,
                                              StringBuffer orgin) {
        // treeMap参数有效性验证
        if (params == null) {
            return null;
        }

        Map<String, String> treeMap = new TreeMap<String, String>();
        treeMap.putAll(params);
        // 名值字符参数无间隔拼接-迭代器使用
        Iterator<String> iter = treeMap.keySet().iterator();
        while (iter.hasNext()) {
            String name = iter.next();
            orgin.append(name).append(params.get(name));
        }

        return orgin;
    }

    /**
     * 保持插入顺序而使用LinkedHashMap重载同名方法
     */
    private static StringBuffer getBeforeSign(
            LinkedHashMap<String, String> params, StringBuffer orgin) {
        // treeMap参数有效性验证
        if (params == null) {
            return null;
        }

        Map<String, String> treeMap = new TreeMap<String, String>();
        treeMap.putAll(params);
        // 名值字符参数无间隔拼接-迭代器使用
        Iterator<String> iter = treeMap.keySet().iterator();
        while (iter.hasNext()) {
            String name = iter.next();
            orgin.append(name).append(params.get(name));
        }

        return orgin;
    }

    /** ---------- 菜鸟异常单查询接口（聚石塔API规范） End ---------- */

    /** ---------- 菜鸟裹裹订单推送接口（TOP-API规范） Start ---------- */

    /**
     * 给TOP请求签名。
     * <p>
     * 所有字符型的TOP请求参数
     *
     * @param secret 签名密钥
     * @return 签名
     * @throws IOException
     */
    public static String signTopRequest(String param, String secret)
            throws IOException {

        // 第三步：使用MD5加密
        byte[] bytes = encryptMD5(param.getBytes("utf-8"));

        // 第四步：把二进制转化为大写的十六进制
        return byte2hex(bytes);
    }

    public static byte[] encryptMD5(byte[] data) throws IOException {
        byte[] bytes = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            bytes = md.digest(data);
        } catch (GeneralSecurityException gse) {
            throw new IOException(gse.getMessage());
        }
        return bytes;
    }

    public static String topbyte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }

    /**
     * ---------- 菜鸟裹裹订单推送接口（TOP-API规范） End ----------
     */

    public static void main(String[] args) {
        long ts = System.currentTimeMillis();
        System.out.println(ts);

        String txt = "{\"logisticCompanyID\":\"DEPPON\",\"logisticID\":\"SD20130523036”}cba1231376620960488";

        String result = SecurityUtil.getCommonDigest(txt, "utf-8");
        System.out.println(result);
        String appkey = "xbkgdeppon20160921";
        System.out.println(SecurityUtil.getMD5Str(appkey));
    }

}